package cn.microven.mindmap.components.node;

import cn.microven.mindmap.components.control.MapNodeLabel;
import cn.microven.mindmap.components.control.MapNodeTextArea;
import cn.microven.mindmap.struture.MindMap;
import javafx.beans.property.*;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Shape;
import javafx.scene.text.Font;
import javafx.util.Pair;

import java.time.Instant;
import java.util.ArrayList;

/**
 * 思维导图节点父类（抽象）
 * 包含节点的基本操作
 * 泛型 T 代表节点形状，需要在子类中通过 initShape() 方法具体实现
 *
 *
 * @author 吴博维
 * @version 1.0
 */
abstract public class AbstractMapNode<T extends Shape> extends AnchorPane implements Cloneable {

    /**
     * 节点文本
     */
    protected MapNodeLabel text = new MapNodeLabel();

    /**
     * 节点层级
     */
    protected int level = 0;

    /**
     * 节点形状
     */
    protected T shape;

    /**
     * 输入框
     */
    protected MapNodeTextArea textArea = new MapNodeTextArea();

    /**
     * 状态
     */
    protected BooleanProperty isEditing = new SimpleBooleanProperty();

    /**
     * 子节点
     */
    protected ArrayList<AbstractMapNode> childrenNode = new ArrayList<>();


    protected AbstractMapNode parentNode = null;


//    protected NodeContextMenu context = new NodeContextMenu();

    public AbstractMapNode() {
        super();
        //添加形状和文本
        initShape();
        this.getChildren().add(shape);
        this.getChildren().add(text);
        this.getChildren().add(textArea);
        this.text.setAlignment(Pos.CENTER);

        //设置内边距
        text.setPadding(new Insets(10, 10, 10, 10));
        //设置初始宽度
        text.setMinWidth(100);


        //设置背景色
        sizeBind();
        hideTextArea();

        //输入框切换
        this.text.setOnMouseClicked(mouseEvent -> {
            if (mouseEvent.getClickCount() == 2 && mouseEvent.getButton() == MouseButton.PRIMARY)
                showTextArea();
            if (mouseEvent.getClickCount() == 1 && !isFocused()) {
//                select();
                requestFocus();
            }
        });

        this.textArea.setOnMouseClicked(mouseEvent -> {
            if (mouseEvent.getClickCount() == 2 && !mouseEvent.isControlDown()) {
                hideTextArea( );
            }
        });

        //属性绑定
        this.text.textProperty().bindBidirectional(textArea.textProperty());

        this.focusedProperty().addListener(((observableValue, isLose, isFocus) -> {
            if (isFocus) {
                select();
            }
            else {
                unselect();
            }
        }));

        textArea.focusedProperty().addListener((observableValue, isLose, isFocus)->{
            if (!isFocus) {
                this.unselect();
            }
        });

    }

    public void setFontSize(int size) {
        this.text.setFontSize(size);
    }

    public StringProperty textProperty() {
        return this.text.textProperty();
    }

    public int getFontSize() {
        return this.text.getFontSize();
    }

    public String getFontFamily() {return this.text.getFontFamily();}

    public Color getBackgroundColor() {return (Color)this.shape.getFill();}

    public SimpleIntegerProperty fontSizeProperty() {
        return this.text.fontSizeProperty();
    }

    protected void sizeBind() {
        //文字宽度与节点宽度、输入框宽度绑定
        text.heightProperty().addListener((observableValue, number, t1) -> {
            setShapeHeight((Double) t1);
            this.setHeight((Double) t1);
            this.textArea.setAreaHeight((Double) t1);
        });
        text.widthProperty().addListener((observableValue, number, t1) -> {
            setShapeWidth((Double) t1);
            this.setWidth((Double) t1);
            this.textArea.setAreaWidth((Double) t1);
        });
    }

    /**
     * 初始化节点内的形状
     */
    abstract protected void initShape();

    /**
     * 设置形状宽度
     *
     * @param shapeWidth 形状宽度
     */
    abstract protected void setShapeWidth(double shapeWidth);

    /**
     * 获取形状宽度
     *
     * @return 形状宽度
     */
    abstract protected double getShapeWidth();


    /**
     * 设置形状高度
     *
     * @param shapeHeight 形状高度
     */
    abstract protected void setShapeHeight(double shapeHeight);

    /**
     * 获取形状高度
     *
     * @return 形状高度
     */
    abstract protected double getShapeHeight();

    /**
     * 获取形状
     * @return 节点的 Shape
     */
    public T getNodeShape() {
        return shape;
    }

    public void setText(String text) {
        this.text.setText(text);
    }

    public String getText() {
        return this.text.getText();
    }

    public void setLabelWidth(double width) {
        this.text.setMinWidth(width);
        this.text.setMaxWidth(width);
    }

    public void setLabelHeight(double height) {
        this.text.setMinHeight(height);
        this.text.setMaxHeight(height);
    }

    public void setBackgroundColor(Color color) {
        shape.setFill(color);
    }

    public void setFontColor(Color color) {
        this.text.setTextFill(color);
    }

    public void setFontFamily(String family) {this.text.setFontFamily(family);}

    public void hideTextArea() {
        textArea.setDisable(true);
        textArea.setVisible(false);
    }

    public void showTextArea() {
        textArea.setDisable(false);
        textArea.setVisible(true);
        textArea.requestFocus();
    }

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public Pair<Double, Double> getLeftIntersection() {
        return new Pair<>(this.getLayoutX(),this.getLayoutY()+getShapeHeight()/2.0);
    }

    public Pair<Double, Double> getRightIntersection() {
        return new Pair<>(this.getLayoutX()+getShapeWidth(),this.getLayoutY()+getShapeHeight()/2.0);
    }

    public Pair<Double, Double> getTopIntersection() {
        return new Pair<>(this.getLayoutX()+getShapeWidth()/2.0,this.getLayoutY());
    }

    public Pair<Double, Double> getBottomIntersection() {
        return new Pair<>(this.getLayoutX()+getShapeWidth()/2.0,this.getLayoutY()+getShapeHeight());
    }

    public AbstractMapNode getParentNode() {
        return parentNode;
    }

    public void setParentNode(AbstractMapNode parentNode) {
        this.parentNode = parentNode;
    }

    public ArrayList<AbstractMapNode> getChildrenNode() {
        return childrenNode;
    }

    public void setChildrenNode(ArrayList<AbstractMapNode> childrenNode) {
        this.childrenNode = childrenNode;
    }

    public boolean hasChildrenNode() {
        return !this.childrenNode.isEmpty();
    }

    public boolean hasParent() {
        return this.parentNode != null;
    }

    public Color getShapeColor() {
        return (Color)this.shape.getFill();
    }

    public void setShapeColor(Color color) {
        this.shape.setFill(color);
    }

    public Color getFontColor() {return (Color)this.text.getTextFill();}

    public MapNodeTextArea getTextArea(){
      return this.textArea;
    }

    public MapNodeLabel getLabel(){
        return this.text;
    }

    public void select() {
        MindMap.getInstance().select(this);
    }

    public void appendSelectedStyle() {
        Border border = new Border(new BorderStroke(Paint.valueOf("red"), BorderStrokeStyle.SOLID, null, new BorderWidths(1)));
        this.setBorder(border);
    }

    public void deleteSelectedStyle() {
        this.setBorder(null);
    }

    public void unselect() {
        hideTextArea();
    }

    /**
     * 圆角
     * @return 圆角像素值
     */
    abstract public double getRadius();

    /**
     * 设置圆角弧度
     */
    abstract public void setRadius(double radius);

    public boolean isIsEditing() {
        return isEditing.get();
    }

    public BooleanProperty isEditingProperty() {
        return isEditing;
    }
}